/**
 * 统计指定目录下代码行数及注释率
 *
 * 用法: node count.js <路径> [后缀名]...
 * 后缀名不填的话默认为统计 .js .ts 和 .vue 文件
 *
 * 示例 [统计 ./src 下的 js/ts/vue 文件]: node count.js ./src
 * 示例 [统计 ./src 下的 vue 文件]: node count.js ./src .vue
 */

const fs = require('fs')
let path = require('path')

// 获取命令行参数
const argv = process.argv.splice(2)
// 验证参数个数
if (argv.length === 0) {
  console.log('请提供至少一个路径参数！');
  process.exit(1);
}
// 第一个参数是路径
const rootPath = argv[0]
// 后面的所有参数都是文件后缀
let types = argv.splice(1)
if (types.length === 0) types = ['.js', '.ts', '.vue','.java','.py','.xml','.kt']
// 需要过滤的文件夹
const filter = ['/node_modules','/ucf-publish', '/dist', '/build','/public','/target','/bin']
// 总计
let total = {
  file: 'total',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}

// 各种文件类型的总计
let kttotal = {
  file: 'kotlin',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}

let xmltotal = {
  file: 'xml',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}

let pytotal = {
  file: 'python',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}

let javatotal = {
  file: 'java',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}


let vuetotal = {
  file: 'vue',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}


let jstotal = {
  file: 'javascript',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}

let tstotal = {
  file: 'typescript',
  length: 0,
  comment: 0,
  empty: 0,
  eloc:0,
  commentRatio: 1,
  emptyRatio: 1
}

// 统计结果
let result = []

/**
 * 对指定文件进行统计
 * 包括获取文件行数、注释及计算注释率
 *
 * @param {string} path 文件路径
 */
async function count (filepath) {
  const filetype = path.extname(filepath)
  const rep = await fs.readFileSync(filepath).toString()
  const lines = rep.split('\n')

  // 匹配出注释的行数
  const commentNum = lines.filter(line => new RegExp('^(//|/\\*|\\*|\\*/)', 'g').test(line.trimStart())).length

  
  // 匹配出空行数
  const emptyNum = lines.filter(line => new RegExp('^(\r|\n\r|\n$/)', 'g').test(line)).length
  file = filepath.substring(filepath.lastIndexOf("/")+1)
  //不列出每个文件的统计数据了
  /*
  result.push({
    file,
    length: lines.length,
    comment: commentNum,
    empty:emptyNum,
    eloc: lines.length-commentNum-emptyNum,
    commentRatio: (Math.round(commentNum / lines.length * 10000) / 100) + '%',
    emptyRatio: (Math.round(emptyNum / lines.length * 10000) / 100) + '%'
  })
  */
  updateTotal(filetype,lines.length, commentNum,emptyNum)
}

/**
 * 更新总计信息
 *
 * @param {string} filetype 文件类型
 * @param {number} length 新增行数
 * @param {number} comment 新增注释
 * @param {number} empty 新增空行
 */
function updateTotal (filetype,length, comment , empty) {
  total.length += length
  total.comment += comment
  total.empty += empty
  total.eloc += length-comment-empty
  total.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
  total.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'

  switch (filetype){
    case '.js':
      jstotal.length += length
      jstotal.comment += comment
      jstotal.empty += empty
      jstotal.eloc += length-comment-empty
      jstotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      jstotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'
      break;
    case '.ts':
      tstotal.length += length
      tstotal.comment += comment
      tstotal.empty += empty
      tstotal.eloc += length-comment-empty
      tstotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      tstotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'
      break;
    case '.vue':
      vuetotal.length += length
      vuetotal.comment += comment
      vuetotal.empty += empty
      vuetotal.eloc += length-comment-empty
      vuetotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      vuetotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'
      break;
    case '.java':
      javatotal.length += length
      javatotal.comment += comment
      javatotal.empty += empty
      javatotal.eloc += length-comment-empty
      javatotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      javatotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'
      break;
    case '.py':
      pytotal.length += length
      pytotal.comment += comment
      pytotal.empty += empty
      pytotal.eloc += length-comment-empty
      pytotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      pytotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'      
      break;
    case '.xml':
      xmltotal.length += length
      xmltotal.comment += comment
      xmltotal.empty += empty
      xmltotal.eloc += length-comment-empty
      xmltotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      xmltotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'      
      break;
    case '.kt':
      kttotal.length += length
      kttotal.comment += comment
      kttotal.empty += empty
      kttotal.eloc += length-comment-empty
      kttotal.commentRatio = (Math.round(total.comment / total.length * 10000) / 100) + '%'
      kttotal.emptyRatio = (Math.round(total.empty / total.length * 10000) / 100) + '%'
      break;
    default:;
  }

}

/**
 * 递归所有文件夹统计
 *
 * @param {string} pt 根目录
 */
async function start (pt) {
  fs.readdirSync(pt).map(file => `${pt}/${file}`)
    .forEach(file => {
      const stat = fs.statSync(file)
      // 是文件夹就递归
      if (stat.isDirectory()) {
        let shortdir = pt.substring(pt.lastIndexOf("/")); 
        //跳过需要排除的目录,以.开头的隐藏目录，以及filter数组中的目录
        if (shortdir.indexOf('.')==0) return;
        if (filter.indexOf(shortdir) !== -1) return;
        return start(file)
      }
      // 是文件并且后缀名符合就执行统计
      if (types.indexOf(path.extname(file)) !== -1) count(file)
    })
}

(async () => {
  await start(rootPath)
  if (xmltotal.length>0) result.push(xmltotal)
  if (jstotal.length>0) result.push(jstotal)
  if (kttotal.length>0) result.push(kttotal)
  if (vuetotal.length>0) result.push(vuetotal)
  if (tstotal.length>0) result.push(tstotal)
  if (javatotal.length>0) result.push(javatotal)
  if (pytotal.length>0) result.push(pytotal)
  result.push(total)
  result.push({
    file: '文件',
    length: "总行数",
    comment: "注释行",
    empty: "空行",
    eloc:'有效代码行',
    commentRatio: "注释占比",
    emptyRatio: "空行占比"
  })
  console.table(result)
})()

